package com.atguigu.aiproject.service.impl;

import com.atguigu.aiproject.mapper.UserMapper;
import com.atguigu.aiproject.entity.ChatMessage;
import com.atguigu.aiproject.entity.ChatSession;
import com.atguigu.aiproject.entity.User;
import com.atguigu.aiproject.service.ChatMessageService;
import com.atguigu.aiproject.service.ChatService;
import com.atguigu.aiproject.service.ChatSessionService;
import com.atguigu.aiproject.vo.PageResult;
import com.atguigu.aiproject.websocket.entity.WebSocketMessage;
import com.atguigu.aiproject.websocket.handler.ChatWebSocketHandler;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.Duration;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Collections;
import java.util.List;

@Service
@Slf4j
public class ChatServiceImpl implements ChatService {

    @Autowired
    private ChatMessageService chatMessageService;

    @Autowired
    private ChatSessionService chatSessionService;

    @Autowired
    private UserMapper userMapper;

    @Autowired
    @Lazy   // 解决循环依赖
    private ChatWebSocketHandler chatWebSocketHandler;

    @Autowired
    private RabbitTemplate rabbitTemplate;

    @Autowired
    private RedisTemplate<String, Object> redisTemplate;

    @Autowired
    private ObjectMapper objectMapper;

    // 发送消息
    @Override
    @Transactional
    public void sendMessage(ChatMessage message) {
        // 数据校验
        if (message.getSenderId() == null || message.getReceiverId() == null) {
            throw new IllegalArgumentException("发送者或接收者ID不能为空");
        }
        if (message.getSenderId().equals(message.getReceiverId())) {
            throw new IllegalArgumentException("不能给自己发送消息");
        }
        if (message.getContent() == null || message.getContent().trim().isEmpty()) {
            throw new IllegalArgumentException("消息内容不能为空");
        }

        // 校验用户存在性
        validateUserExists(message.getSenderId());
        validateUserExists(message.getReceiverId());

        // 设置消息状态和时间
        message.setStatus(ChatMessage.MessageStatus.SENT);
        message.setSendTime(LocalDateTime.now());

        // 保存到数据库
        chatMessageService.save(message);
        log.info("消息保存成功: 发送者 {}, 接收者 {}, 消息ID {}",
                message.getSenderId(), message.getReceiverId(), message.getId());

        // 更新会话
        updateChatSession(message);

        // 发送WebSocket消息
        WebSocketMessage wsMessage = new WebSocketMessage();
        wsMessage.setType("MESSAGE");
        wsMessage.setMessage(message);
        wsMessage.setTimestamp(LocalDateTime.now());

        // 发送给接收者（如果在线）
        boolean receiverOnline = chatWebSocketHandler.isUserOnline(message.getReceiverId());
        if (receiverOnline) {
            chatWebSocketHandler.sendMessageToUser(message.getReceiverId(), wsMessage);
            log.debug("实时消息发送给在线用户: {}", message.getReceiverId());
        } else {
            log.debug("接收者 {} 不在线，消息已存储", message.getReceiverId());
            // 可以在这里添加离线推送逻辑
        }

        // 发送到消息队列进行异步处理（如推送通知等）
        try {
            String jsonMessage = objectMapper.writeValueAsString(wsMessage);
            rabbitTemplate.convertAndSend("chat.exchange", "chat.message", jsonMessage);
            log.debug("消息发送到RabbitMQ成功");
        } catch (JsonProcessingException e) {
            log.error("消息序列化失败: {}", e.getMessage());
            // 不抛出异常，不影响主流程
        }

        // 缓存最近消息
        cacheRecentMessage(message);
    }

    // 获取聊天记录 - 基于游标的分页（更适合聊天场景）
    @Override
    //TODO:新增一个游标分页对象
    public PageResult<ChatMessage> getChatHistory(Integer userId, Integer targetUserId,
                                                  LocalDateTime before, Integer limit) {
        // 参数校验和默认值设置
        if (limit == null || limit <= 0) {
            limit = 20;
        }
        if (limit > 100) {
            limit = 100; // 限制最大查询数量
        }
        if (before == null) {
            before = LocalDateTime.now();
        }

        // 权限校验
        if (!hasChatPermission(userId, targetUserId)) {
            throw new SecurityException("无权限查看该聊天记录");
        }

        // 查询数据
        QueryWrapper<ChatMessage> queryWrapper = new QueryWrapper<>();
        queryWrapper.and(wrapper -> wrapper
                        .eq("sender_id", userId).eq("receiver_id", targetUserId)
                        .or()
                        .eq("sender_id", targetUserId).eq("receiver_id", userId))
                .lt("send_time", before)
                .orderByDesc("send_time")
                .last("LIMIT " + limit);

        List<ChatMessage> messages = chatMessageService.list(queryWrapper);
        log.debug("获取聊天记录: 用户 {} 与 {}，查询到 {} 条记录", userId, targetUserId, messages.size());

        // 计算是否有更多数据
        boolean hasMore = false;
        if (!messages.isEmpty() && messages.size() == limit) {
            // 如果返回的消息数量等于限制数量，说明可能还有更多数据
            LocalDateTime earliestTime = messages.get(0).getSendTime(); // 最早的消息时间

            QueryWrapper<ChatMessage> moreWrapper = new QueryWrapper<>();
            moreWrapper.and(wrapper -> wrapper
                            .eq("sender_id", userId).eq("receiver_id", targetUserId)
                            .or()
                            .eq("sender_id", targetUserId).eq("receiver_id", userId))
                    .lt("send_time", earliestTime);

            // 使用 count 方法检查是否存在更多数据
            hasMore = chatMessageService.count(moreWrapper) > 0;
            log.debug("检查更多数据: {}", hasMore ? "有更多数据" : "没有更多数据");
        }

        // 反转列表，使时间正序（最新的在最后）
        Collections.reverse(messages);

        // 对于游标分页，我们不需要传统的分页信息
        Integer total = null; // 不计算总数，避免性能问题
        int current = 1;
        Integer size = limit;
        Integer pages = hasMore ? current + 1 : current; // 如果有更多数据，页数+1

        // 生成搜索ID
        String searchId = generateSearchId(userId, targetUserId, before, limit);

        return new PageResult<>(messages, total, current, size, pages, searchId);
    }

    // 生成搜索ID的方法
    private String generateSearchId(Integer userId, Integer targetUserId,
                                    LocalDateTime before, Integer limit) {
        String timestamp = before.format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss"));
        return String.format("chat_%d_%d_%s_%d", userId, targetUserId, timestamp, limit);
    }

    // 标记消息为已读
    @Override
    @Transactional
    public void markMessagesAsRead(Integer userId, Integer targetUserId) {
        // 权限校验
        if (!hasChatPermission(userId, targetUserId)) {
            throw new SecurityException("无权限操作该聊天记录");
        }

        // 更新消息状态为已读
        ChatMessage updateMessage = new ChatMessage();
        updateMessage.setStatus(ChatMessage.MessageStatus.READ);
        updateMessage.setReadTime(LocalDateTime.now());

        QueryWrapper<ChatMessage> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("sender_id", targetUserId)
                .eq("receiver_id", userId)
                .eq("status", ChatMessage.MessageStatus.SENT.getCode());

        boolean updateSuccess  = chatMessageService.update(updateMessage, queryWrapper);
        if(updateSuccess){
            log.debug("已读消息更新成功: 发送方 {}, 接收方 {}", targetUserId, userId);
        }else{
            log.debug("已读消息更新失败: 发送方 {}, 接收方 {}", targetUserId, userId);
        }

        // 更新会话未读计数
        updateSessionUnreadCount(userId, targetUserId);

        // 发送已读回执（如果对方在线）
        if (chatWebSocketHandler.isUserOnline(targetUserId)) {
            WebSocketMessage wsMessage = new WebSocketMessage();
            wsMessage.setType("READ");
            wsMessage.setSenderId(userId);
            wsMessage.setReceiverId(targetUserId);
            wsMessage.setTimestamp(LocalDateTime.now());

            chatWebSocketHandler.sendMessageToUser(targetUserId, wsMessage);
            log.debug("已读回执发送给用户: {}", targetUserId);
        }
    }

    // 更新用户在线状态
    @Override
    public void updateUserOnlineStatus(Integer userId, boolean isOnline) {
        User user = new User();
        user.setId(userId);
        user.setOnlineStatus(isOnline);
        user.setLastOnlineTime(LocalDateTime.now());

        int result = userMapper.updateById(user);
        if (result > 0) {
            log.debug("更新用户在线状态: 用户 {} {}", userId, isOnline ? "在线" : "离线");
        }

        // 缓存在线状态到Redis
        String key = "user:online:" + userId;
        if (isOnline) {
            redisTemplate.opsForValue().set(key, "true", Duration.ofMinutes(5));
        } else {
            redisTemplate.delete(key);
        }
    }

    // 获取用户会话列表
    @Override
    public List<ChatSession> getUserSessions(Integer userId) {
        // 实现获取用户所有会话的逻辑
        QueryWrapper<ChatSession> queryWrapper = new QueryWrapper<>();
        queryWrapper.and(wrapper -> wrapper
                        .eq("user1_id", userId)
                        .or()
                        .eq("user2_id", userId))
                .orderByDesc("last_message_time");

        List<ChatSession> sessions = chatSessionService.list(queryWrapper);

        // 为每个会话设置对方用户信息
        for (ChatSession session : sessions) {
            Integer otherUserId = session.getUser1Id().equals(userId) ?
                    session.getUser2Id() : session.getUser1Id();
            // 可以在这里查询对方用户信息并设置到会话中
        }

        return sessions;
    }

    // 校验用户是否存在
    private void validateUserExists(Integer userId) {
        User user = userMapper.selectById(userId);
        if (user == null) {
            throw new IllegalArgumentException("用户不存在: " + userId);
        }
    }

    // 检查聊天权限
    private boolean hasChatPermission(Integer userId, Integer targetUserId) {
        // 简单的权限检查：双方用户都存在就有权限
        // 实际业务中可以扩展，如检查黑名单、好友关系等
        try {
            validateUserExists(userId);
            validateUserExists(targetUserId);
            return true;
        } catch (IllegalArgumentException e) {
            return false;
        }
    }

    // 更新聊天会话
    private void updateChatSession(ChatMessage message) {
        Integer user1Id = message.getSenderId();
        Integer user2Id = message.getReceiverId();

        // 确保user1Id是较小的那个，保证唯一性
        if (user1Id.compareTo(user2Id) > 0) {
            Integer temp = user1Id;
            user1Id = user2Id;
            user2Id = temp;
        }

        ChatSession session = chatSessionService.getByUserPair(user1Id, user2Id);
        if (session == null) {
            session = new ChatSession();
            session.setUser1Id(user1Id);
            session.setUser2Id(user2Id);
            session.setUnreadCount(0);
            session.setCreateTime(LocalDateTime.now());
            chatSessionService.save(session);
            log.debug("创建新会话: {} 与 {}", user1Id, user2Id);
        }

        // 更新会话信息
        session.setLastMessageId(message.getId());

        // 截断过长的消息内容
        String content = message.getContent();
        if (content.length() > 100) {
            content = content.substring(0, 100) + "...";
        }
        session.setLastMessageContent(content);

        session.setLastMessageTime(message.getSendTime());
        session.setUpdateTime(LocalDateTime.now());

        // 增加未读计数（对于接收者）
        // 注意：这里假设未读计数是针对 user1Id 的
        // 如果您的业务逻辑不同，需要调整
        if (user1Id.equals(message.getReceiverId())) {
            session.setUnreadCount(session.getUnreadCount() + 1);
            log.debug("增加未读计数: 会话 {} 未读计数 {}", session.getId(), session.getUnreadCount());
        }

        chatSessionService.updateById(session);
    }

    private void updateSessionUnreadCount(Integer userId, Integer targetUserId) {
        // 重置未读计数
        Integer user1Id = userId.compareTo(targetUserId) < 0 ? userId : targetUserId;
        Integer user2Id = userId.compareTo(targetUserId) < 0 ? targetUserId : userId;

        ChatSession session = chatSessionService.getByUserPair(user1Id, user2Id);
        if (session != null) {
            int oldUnreadCount = session.getUnreadCount();
            session.setUnreadCount(0);
            session.setUpdateTime(LocalDateTime.now());
            chatSessionService.updateById(session);
            log.debug("重置未读计数: 会话 {} 从未读 {} 重置为 0", session.getId(), oldUnreadCount);
        }
    }

    /**
     * 缓存最近一条消息
     */
    private void cacheRecentMessage(ChatMessage message) {
        String key = "recent:message:" + message.getSenderId() + ":" + message.getReceiverId();
        try {
            String jsonMessage = objectMapper.writeValueAsString(message);
            redisTemplate.opsForValue().set(key, jsonMessage, Duration.ofDays(1));
        } catch (JsonProcessingException e) {
            log.error("缓存最近消息失败: {}", e.getMessage());
        }
    }

    /**
     * 获取用户的未读消息总数
     */
    @Override
    public Integer getTotalUnreadCount(Integer userId) {
        QueryWrapper<ChatSession> queryWrapper = new QueryWrapper<>();
        queryWrapper.and(wrapper -> wrapper
                .eq("user1_id", userId)
                .or()
                .eq("user2_id", userId));

        List<ChatSession> sessions = chatSessionService.list(queryWrapper);

        // 这里需要根据业务逻辑计算未读总数
        // 假设未读计数是针对 user1Id 的，需要调整逻辑
        return sessions.stream()
                .mapToInt(ChatSession::getUnreadCount)
                .sum();
    }

    /**
     * 清理用户聊天记录（管理员功能）
     */
    @Override
    @Transactional
    public void clearChatHistory(Integer userId, Integer targetUserId) {
        // 权限校验
        if (!hasChatPermission(userId, targetUserId)) {
            throw new SecurityException("无权限清理该聊天记录");
        }

        QueryWrapper<ChatMessage> queryWrapper = new QueryWrapper<>();
        queryWrapper.and(wrapper -> wrapper
                .eq("sender_id", userId).eq("receiver_id", targetUserId)
                .or()
                .eq("sender_id", targetUserId).eq("receiver_id", userId));

        boolean removeSuccess  = chatMessageService.remove(queryWrapper);
        if(removeSuccess){
            log.info("清理聊天记录: {} 与 {}", userId, targetUserId);
        }else{
            log.warn("清理聊天记录失败: {} 与 {}", userId, targetUserId);
        }

        // 同时清理会话
        Integer user1Id = userId.compareTo(targetUserId) < 0 ? userId : targetUserId;
        Integer user2Id = userId.compareTo(targetUserId) < 0 ? targetUserId : userId;

        QueryWrapper<ChatSession> sessionWrapper = new QueryWrapper<>();
        sessionWrapper.eq("user1_id", user1Id).eq("user2_id", user2Id);

        chatSessionService.remove(sessionWrapper);
        log.info("清理会话: {} 与 {}", user1Id, user2Id);
    }
}